﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GenericGA.extrandom;

namespace GenericGA.generationmaker.crossover
{
    /// <summary>
    /// Cross 2 chromosomes based on a specified number of crossover points.
    /// </summary>
    public class NPointCrossover : Crossover
    {

        /// <summary>
        /// A random number generator.
        /// </summary>
        private readonly ExtRandom randGen;

        /// <summary>
        /// The number of crossover points to use.
        /// </summary>
        public int NumCrossoverPoints
        {
            get
            {
                return numCrossoverPoints;
            }

            set
            {
                if (value < 1)
                {
                    throw new ArgumentException();
                }
                numCrossoverPoints = value;
            }
        }
        private int numCrossoverPoints;

        /// <summary>
        /// Constructor to create an NPointCrossover object.
        /// </summary>
        /// <param name="randGen">A random number generator.</param>
        /// <param name="numCrossoverPoints">The number of crossover points to use.</param>
        public NPointCrossover(ExtRandom randGen, int numCrossoverPoints)
        {
            this.randGen = randGen;
            NumCrossoverPoints = numCrossoverPoints;
        }

        /// <summary>
        /// Cross over the genetic material of two chromosomes by overwriting them.
        /// </summary>
        /// <param name="bits1">One of the 2 chromosomes to cross over. Will be modified.</param>
        /// <param name="bits2">One of the 2 chromosomes to cross over. Will be modified.</param>
        public override void Cross(List<ulong> offspring1, List<ulong> offspring2)
        {
            Crossover.MakeLengthsEqual(randGen, offspring1, offspring2);
            int[] cps = new int[numCrossoverPoints];
            int lastCP = 0;
            int remainingCP = numCrossoverPoints;
            for (int i = 0; i < numCrossoverPoints; i++)
            {
                remainingCP--;
                lastCP = randGen.Next(lastCP + 1, offspring1.Count * 64 - remainingCP);
                cps[i] = lastCP;
            }
            Crossover.SwapBits(offspring1, offspring2, cps);
        }

    }
}
